#include <iostream>
#include <string>
#include <websocketpp/config/asio.hpp>
#include <websocketpp/server.hpp>
#include <websocketpp/common/thread.hpp>
#include <list>

typedef websocketpp::server<websocketpp::config::asio> server;
using websocketpp::lib::bind;
using websocketpp::lib::error_code;
using websocketpp::lib::ref;
using websocketpp::lib::thread;

void _recv(server &s, websocketpp::connection_hdl hdl, server::message_ptr msg)
{
    std::cout << "server-recv: " << msg->get_payload() << std::endl;
}

void _on_open(std::list<websocketpp::connection_hdl> &list, websocketpp::connection_hdl hdl)
{
    list.push_back(hdl);
    std::cout << "open: " << hdl.lock().get() << std::endl;
}

void _on_close(std::list<websocketpp::connection_hdl> &list, websocketpp::connection_hdl hdl)
{
    list.remove_if([&hdl](auto &item)
                   { return item.lock().get() == hdl.lock().get(); });
    std::cout << "close: " << hdl.lock().get() << std::endl;
}

int main(int argc, char const *argv[])
{
    server s;

    std::list<websocketpp::connection_hdl> connList;

    s.set_access_channels(websocketpp::log::alevel::none);
    s.set_message_handler(bind(&_recv, ref(s), std::placeholders::_1, std::placeholders::_2));
    s.set_open_handler(bind(&_on_open, ref(connList), std::placeholders::_1));
    s.set_close_handler(bind(&_on_close, ref(connList), std::placeholders::_1));

    s.init_asio();
    s.start_perpetual();
    s.listen(9002);
    s.start_accept();

    error_code e;

    thread t(&server::run, &s);
    std::string msg;
    std::cout << "server start, press ctrl+D to quit!" << std::endl;

    while (std::cin >> msg)
    {
        std::cout << "send: " << msg << std::endl;
        for (auto &conn : connList)
        {
            s.send(conn, msg, websocketpp::frame::opcode::text);
        }
    }
    std::cout << "server stop!" << std::endl;
    s.stop_perpetual();
    s.stop();
    t.join();

    return 0;
}
